<!DOCTYPE html><html><head>
<style>
body {
    background-color: #222;
    color: white;
    margin: 0;
}
canvas {
    background-color: #000;
}
#wrapper {
    width: 334px;
    margin: 0 auto;
}
#wrapper div {
    width: 300px;
    margin: .5em;
    padding: .5em;
    border: 1px solid #333;
    display: inline-block;
    text-align: center;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
@media only screen and (min-width: 668px) {
    #wrapper {
        width: 668px;
    }
}
@media only screen and (min-width: 1002px) {
    #wrapper {
        width: 1002px;
    }
}
</style>
</head>
<body>
<script type="text/javascript" src="http://wow.techbrood.com/libs/jquery/jquery-2.1.1.min.js"></script><script src="http://wow.techbrood.com/libs/jquery/jquery-1.11.1.min.js"></script>
<div id="wrapper"> </div>
<script>
var wrapper = document.getElementById("wrapper");

var rad = Math.PI / 180;
var frames = 0;
var Ry = []; // canvases array

function createCanvas(A, B, C, I) {
    this.A = A; // for the hypocycloid
    this.B = B; // for the hypocycloid
    this.C = C; // num particles
    this.I = I; // increment
    this.a = this.A * I;
    this.b = this.B * I;
    this.r = 6; // particle radius

    // createElement
    this.parent = document.createElement("div");
    this.c = document.createElement("canvas");
    this.parent.appendChild(this.c);
    var html = "A = " + A + "; B = " + B + "; C = " + C;
    var p = document.createElement("p");
    p.innerHTML = html;
    this.parent.appendChild(p);
    wrapper.appendChild(this.parent);

    // getContext
    this.ctx = this.c.getContext("2d");
    this.cw = this.c.width = 300,
        this.cx = this.cw / 2;
    this.ch = this.c.height = 280,
        this.cy = this.ch / 2;
    this.ctx.strokeStyle = "rgba(255,255,255,.25)";
    this.ctx.fillStyle = "#fff";

    this.drawHypocycloid = function() {
        this.ctx.beginPath();
        for (var T = 0; T < 360 * this.B; T++) {
            var o = this.hypocycloidPoint(T);
            this.ctx.lineTo(o.x, o.y);
        }
        this.ctx.closePath();
        this.ctx.stroke();
    }

    this.hypocycloidPoint = function(T) {
        var t = T * rad;
        var o = {}
        o.x = this.cx + (this.a - this.b) * Math.cos(t) + this.b * Math.cos((this.a - this.b) / this.b * t);
        o.y = this.cy + (this.a - this.b) * Math.sin(t) - this.b * Math.sin((this.a - this.b) / this.b * t);
        return o;
    }

    this.drawPoint = function(p) {
        this.ctx.beginPath();
        this.ctx.arc(p.x, p.y, this.r, 0, 2 * Math.PI);
        this.ctx.fill();
    }

    this.draw = function() {
        this.ctx.clearRect(0, 0, this.cw, this.ch);
        this.drawHypocycloid();
        var phi = 360 * this.B / this.C;

        for (var i = 0; i < this.C; i++) {
            this.ctx.fillStyle = "hsl(" + (i * 360 / C) + ",90%, 65%)";
            var p = this.hypocycloidPoint(i * phi + frames);
            this.drawPoint(p)
        }
    }

}


Ry.push(new createCanvas(5, 3, 6, 22));
Ry.push(new createCanvas(7, 3, 9, 15));
Ry.push(new createCanvas(8, 3, 9, 15));
Ry.push(new createCanvas(8, 5, 12, 15));
Ry.push(new createCanvas(16, 5, 10, 8));
Ry.push(new createCanvas(16, 5, 20, 8));
Ry.push(new createCanvas(32, 15, 20, 2));
Ry.push(new createCanvas(64, 30, 20, 2));
Ry.push(new createCanvas(64, 30, 20, 8));



function Draw() {
    requestId = window.requestAnimationFrame(Draw);
    frames++;

    for (var c = 0; c < Ry.length; c++) {
        Ry[c].draw();
    }

}
Draw();
</script>

</body>
</html>